Angular在第5版新推出了支援Service worker的功能,主要是可以讓Angular更能符合PWA的概念。
PWA(Progressive Web App)是希望能夠讓Web application盡可能的在各種環境(網路環境、手機作業系統等)下都能順暢且不減功能性的運作。
例如要可以支援離線功能,在使用 App 收信、寫信、刪除信件等動作,都需要將結果丟回伺服器儲存,但在某些環境下並無法一直使用網路連線,因此必須使用一種機制,讓我們仍能順暢的使用這些功能,待網路正常連線,再將剛才所執行的一切動作反應回伺服器。
而Service Worker可以讓Web application做到上面這樣的事情。
要使用Angular Service worker,您必須具有以下Angular和CLI版本:
Web application必須在支援Service worker的Web瀏覽器中運行。
目前支持最新版本的Chrome和Firefox。
其他瀏覽器的支援狀況如下圖(連結):
圖片來源:Browser push notifications using JavaScript
將--service-worker
標誌添加到ng new
命令中:
ng new my-project --service-worker
步驟1:添加service worker package
yarn add @angular/service-worker
步驟2:在CLI中啟用service worker
ng set apps.0.serviceWorker=true
步驟3:導入並註冊service worker 在src/app/app.module.ts
import { ServiceWorkerModule } from '@angular/service-worker';
import { environment } from '../environments/environment';
在app.module.ts
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
ServiceWorkerModule.register('/ngsw-worker.js', {enabled: environment.production})//註冊ServiceWorker腳本的名稱
],
providers: [
CheckForUpdateService,
LogUpdateService,
PromptUpdateService,
],
bootstrap: [AppComponent]
})
export class AppModule { }
步驟4:創建配置文件ngsw-config.json 大多數src/ngsw-config.json
合理的默認值如下:
{
"index": "/index.html",
"assetGroups": [{
"name": "app",
"installMode": "prefetch",
"resources": {
"files": [
"/favicon.ico",
"/index.html"
],
"versionedFiles": [
"/*.bundle.css",
"/*.bundle.js",
"/*.chunk.js"
]
}
}, {
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
"resources": {
"files": [
"/assets/**"
]
}
}]
}
第5步:構建項目
ng build --prod
可以使用Chrome Debug Tool,設置瀏覽器狀態為離線
從Network的資料會可以看到現在HTTP資料的來源是來自於service worker
這個面版可以觀察Service worker的運行狀況
下面是利用SwUpdate來取得現有可用及被啟用的notified的方式
@Injectable()
export class LogUpdateService {
constructor(updates: SwUpdate) {
updates.available.subscribe(event => {
console.log('current version is', event.current);
console.log('available version is', event.available);
});
updates.activated.subscribe(event => {
console.log('old version was', event.previous);
console.log('new version is', event.current);
});
}
}
檢查更新的方式
import { interval } from 'rxjs/observable/interval';
@Injectable()
export class CheckForUpdateService {
constructor(updates: SwUpdate) {
interval(6 * 60 * 60).subscribe(() => updates.checkForUpdate());
}
}
強制更新資料
@Injectable()
export class PromptUpdateService {
constructor(updates: SwUpdate) {
updates.available.subscribe(event => {
if (promptUser(event)) {
updates.activateUpdate().then(() => document.location.reload());
}
});
}
}
我們可以將Service worker想像成像瀏覽器快取或者CDN edge一樣,都是會將網頁資料暫存起來。只是Service worker是將資料存在瀏覽器上。
透過設置src/ngsw-config.json
來設定版本資訊,被分組到同一個版本的文件通常包括HTML,JS和CSS,這些文件的完整性非常重要,因為JS和CSS常常會互相引用並彼此依賴。
例如在index.html
裡可能引用了bundle.js
並呼叫了它的方法startApp()
,如果某次改版我們將startApp()
改名為runApp()
,但是在index.html
裡若是舊的版本,依舊呼叫startApp()
,就會造成執行上的錯誤。
因此快取設定資料的完整性和版本的一致性非常的重要,可以確保ANGULAR在離線執行時可以正常運作。
每次使用者打開或更新網頁時,Angular service worker都會透過ngsw.json
的更新來檢查應用程序的更新。如果有發現有更新的頁面,將會自動下載並緩存,在下次載入網頁時提供。
有關於service worker的debug資訊都在ngsw/
底下,公開的網址為ngsw/state
。 下面是一個ngsw/state
的範例:
NGSW Debug Info:
//這邊是指service worker的Driver狀態,有三種值:NORMAL(正常),EXISTING_CLIENTS_ONLY(舊的快取可安全使用),SAFE_MODE(版存資料失效,所有資料都會由網路提供)
Driver state: NORMAL ((nominal))
//最新清單的SHA hash
Latest manifest hash: eea7f5f464f90789b621170af5a569d6be077e5c
//上次更新檢查
Last update check: never
//版本資訊
=== Version eea7f5f464f90789b621170af5a569d6be077e5c ===
Clients: 7b79a015-69af-4d3d-9ae6-95ba90c79486, 5bc08295-aaf2-42f3-a4cc-9e4ef9100f65
//空閒任務隊列
=== Idle Task Queue ===
Last update tick: 1s496u
Last update run: never
Task queue:
* init post-load (update, cleanup)
//調試日誌
Debug log:
詳細說明請見Service Worker Configuration
Hihi,
Service worker 不是angular的新觀念歐,相反的他比Angular 4/5甚至2更早被提出與實作。
整體上此技術與離線web app 有關,但是從好幾年前PWA web所衍生出來的話題。
基本上不用angular也可以用service worker. 不過現在主流框架可能都會在預設的專案內幫你添加好。
我去年另外寫的一篇可以分享給你
https://blackie1019.github.io/2017/08/01/Using-Service-Worker-to-Optimize-Web-Site-Performance/
謝謝分享!